package com.codemonkey.lq.qd;


import java.util.HashMap;
import java.util.Map;

/**
 * 整个Service流程中的Context
 * 直接仿造了
 * 	1. MyBatis下的org.apache.ibatis.session.Configuration类中的内部静态类StrictMap<V>
 *  2. httl中的Context的概念,,也forge其在httl中的package位置,
 *  虽然不是抽象类，但它是为api服务的，所以基于api与spi分离..但作者并没有在执行接口中直接暴露Context,而是选择了内部转化,
 *  参见AbstractTemplate类中的render方法,它接受到是object类型，然后在内部转化为Context
 *  
 *  TODO 参考下Mybatis的DynamicContext类
 * @author LQ
 *
 */
public final class ServiceContext {

	private final StrictMap<Object> globalContainer = new StrictMap<Object>("global container");
	private final StrictMap<Object> actionResultContainer = new StrictMap<Object>(
			"the container which be used to storage the result that each 'action' which contained in 'service' generate to ");
	private final StrictMap<Object> outParamsContainer = new StrictMap<Object>("this container is used to storage the params which is passed from outside.");
	
	private final String name;

	private ServiceContext(String name) {
		super();
		this.name = name;
		globalContainer.put(KEYS.ActionResultGroup, actionResultContainer);
		globalContainer.put(KEYS.OUT_PARAMETERS, outParamsContainer);
		
		globalContainer.put(KEYS.EXECUTE_CONTEXT, new HashMap<String, Object>(10));
		
	}

	public static ServiceContext newInstance(String name) {
		ServiceContext sc = new ServiceContext(name);
		return sc;
	}

	public Map<String, Object> getActionResultContainer() {
		return getContainer(KEYS.ActionResultGroup);
	}

	public Map<String, Object> getExecuteContextContainer() {
		return getContainer(KEYS.EXECUTE_CONTEXT);
	}

	public Map<String, Object> getOutParamsContainer() {
		return getContainer(KEYS.OUT_PARAMETERS);
	}	

	public Map<String, Object> getContainer(String containerKey) {
		Object container = globalContainer.get(containerKey);
		if (null == container) {
			HashMap<String, Object> newContainer = new HashMap<String, Object>(10);
			globalContainer.put(containerKey, newContainer);
			return newContainer;
		} else {
			return (Map<String, Object>) container;
		}
	}

	/**
	 * 存储在本service中的每个action执行完毕之后的key-value键值对.
	 * @param key
	 * @param value
	 * @return
	 */
	public Object putActionResult(String key, Object value) {
		return actionResultContainer.put(key, value);
	}

	//---------------------------- Properties ------------------------------------
	public String getName() {
		return name;
	}

	//---------------------- override Object Method ------------------------------
	@Override
	public String toString() {
		return String.format(" '%s' : %s ", this.name, globalContainer.toString());
	}

	//----------------------------------------------------------------------------	
	//								STATIC INNER CLASS	
	//----------------------------------------------------------------------------	
	/**
	 * 直接摘抄自MyBatis中的org.apache.ibatis.session.Configuration的同名内部类
	 * @author LQ
	 *
	 * @param <V>
	 */
	protected static class StrictMap<V> extends HashMap<String, V> {

		/**
		 * WARNING : DO NOT MODIFY THE VALUE !!!
		 */
		private static final long serialVersionUID = 910626L;

		private String name;

		public StrictMap(String name, int initialCapacity, float loadFactor) {
			super(initialCapacity, loadFactor);
			this.name = name;
		}

		public StrictMap(String name, int initialCapacity) {
			super(initialCapacity);
			this.name = name;
		}

		public StrictMap(String name) {
			super();
			this.name = name;
		}

		public StrictMap(String name, Map<String, ? extends V> m) {
			super(m);
			this.name = name;
		}

		@SuppressWarnings("unchecked")
		public V put(String key, V value) {
			if (containsKey(key))
				throw new IllegalArgumentException(name + " already contains value for " + key);
			if (key.contains(".")) {
				final String shortKey = getShortName(key);
				if (super.get(shortKey) == null) {
					super.put(shortKey, value);
				} else {
					super.put(shortKey, (V) new Ambiguity(shortKey));
				}
			}
			return super.put(key, value);
		}

		public V get(Object key) {
			V value = super.get(key);
			//			if (value == null) {
			//				throw new IllegalArgumentException(name + " does not contain value for " + key);
			//			}
			if (value instanceof Ambiguity) {
				throw new IllegalArgumentException(
						((Ambiguity) value).getSubject()
								+ " is ambiguous in "
								+ name
								+ " (try using the full name including the namespace, or rename one of the entries)");
			}
			return value;
		}

		private String getShortName(String key) {
			final String[] keyparts = key.split("\\.");
			final String shortKey = keyparts[keyparts.length - 1];
			return shortKey;
		}

		/**
		 * 模拟两可;有歧义的
		 */
		protected static class Ambiguity {
			private String subject;

			public Ambiguity(String subject) {
				this.subject = subject;
			}

			public String getSubject() {
				return subject;
			}
		}
	}

	/**
	 * 名称 <-> 惯例 -> 以 _ 开头和结尾就是为了防止重复
	 * @author LQ
	 *
	 */
	public static class KEYS {
		/**
		 * 存储每个action执行过程中产生的结果,(内部使用!!)
		 */
		static final String ActionResultGroup = "__ACTION_RESULT_GROUP__";

		/**
		 * 本次action执行时的context区域
		 */
		public static final String EXECUTE_CONTEXT = "__EXECUTE_CONTEXT__";

		/**
		 * Web 外部传递来的参数;根节点
		 */
		public static final String OUT_PARAMETERS = "__OUT__";

	}
}
